package sequencer;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import java.rmi.RemoteException;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import common.JoinInfoMsg;
import common.RequestMsg;
import common.Sequencer;

import common.UpdateMsg;

public class SequencerImpl implements Sequencer{

	//private Hashtable<String,ServerUpdate> servers; 

	private int sequenceNum;
	private Hashtable<Integer,Integer> storage;

	private List<UpdateMsg> history;



	public SequencerImpl(){

		//servers = new Hashtable<String,ServerUpdate>();
		sequenceNum = 0;
		storage = new Hashtable<Integer,Integer>();
		history = new ArrayList<UpdateMsg>();

	}



	@Override
	public JoinInfoMsg join(String sender) throws RemoteException {

		JoinInfoMsg joinInfoMsg = null;
		//try{

		//ServerUpdate serverUpdate = (ServerUpdate) Naming.lookup("rmi://"+sender+"/server_update");
		//servers.put(sender, serverUpdate);
		System.out.println("Server "+ sender + " request join information");
		joinInfoMsg = new JoinInfoMsg(sequenceNum,storage);

		//	} catch (Exception ex){
		//	System.err.println("Error on server joining");
		//}

		return joinInfoMsg;
	}



	@Override
	public synchronized void send(String sender, RequestMsg requestMsg) throws RemoteException {
		System.out.printf("Sequencer:  received requestMsg from "+sender+" with dataId=%d and newValue=%d\n", requestMsg.getDataId(),requestMsg.getNewValue());

		UpdateMsg updateMsg = new UpdateMsg(++sequenceNum, requestMsg);
		history.add(updateMsg);
		storage.put(Integer.valueOf(requestMsg.getDataId()), Integer.valueOf(requestMsg.getNewValue()));

		String packetString = String.valueOf(updateMsg.getSequenceNum())+":"+String.valueOf(updateMsg.getRequestMsg().getMsgId())+":"+
				String.valueOf(updateMsg.getRequestMsg().getDataId())+":"+String.valueOf(updateMsg.getRequestMsg().getNewValue());



		//byte[] buf = new byte[256];

		try {
			DatagramSocket socket = new DatagramSocket(4445);
			//InetAddress group = InetAddress.getByName("230.0.0.1");
			InetAddress group = InetAddress.getByName("239.255.0.1");
			DatagramPacket packet = new DatagramPacket(packetString.getBytes(), packetString.getBytes().length, group, 4446);
			System.out.println("Sequencer: Multicasting packet "+packetString+" ...");
			socket.send(packet);
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}




	@Override
	public synchronized List<UpdateMsg> getMissing(String sender, int lastSequenceNum) throws RemoteException {

		List<UpdateMsg> missings = new ArrayList<UpdateMsg>();
		
		int seqNo = lastSequenceNum;

		while(this.sequenceNum >= seqNo){

			for(UpdateMsg updateMsg: history){
				if(updateMsg.getSequenceNum()==seqNo){
					missings.add(updateMsg);
					seqNo++;
					break;
				}

			}
			
			
		}

		return missings;
	}




}
